<?php

namespace Hilaoyu\LaravelExtend\Services\XcfsCient;

use Hilaoyu\LaravelExtend\Supports\Uuid;
use Hilaoyu\LaravelPrivateApi\PrivateApiClient;
use Hilaoyu\Utils\Traits\ErrorsTrait;
use Hilaoyu\Utils\UtilHttp;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

class XcfsClient
{
    use ErrorsTrait;
    const XCFS_SCHEMA ="xcfs";
    const XCFS_URI_PREFIX ="file/response/";

    static public function ServiceUrl()
    {
        return config("xcfs-client.service_url","");
    }
    static public function ApiUrl()
    {
        return config("xcfs-client.api_url", config("xcfs-client.service_url",""));
    }
    static public function IsXcfsUri(string $uri)
    {
        $u = parse_url($uri);
        $xcfs_host = parse_url(static::ServiceUrl(),PHP_URL_HOST);
        if((strtolower(data_get($u, "scheme")) == static::XCFS_SCHEMA) || (strtolower(data_get($u, "host")) == $xcfs_host)){
            return true;
        }
        return false;
    }
    static public function FindAppConf(string $app_id)
    {
        return collect(config("xcfs-client.apps"))->first(function($item) use($app_id){
            return $item["app_id"] == $app_id;
        });
    }

    static public function ParseXcfsUri(string $uri){
        if("" == $uri){
            return null;
        }

        if(!static::IsXcfsUri($uri)){
            return null;
        }


        $u = parse_url($uri);
        $path = data_get($u, "path","");
        $path = trim($path,"/");

        if(!$path){
            return null;
        }
        $app_id = Str::before(Str::after($path,static::XCFS_URI_PREFIX),"/");

        if(!$app_id || !Uuid::verify($app_id)){
            return null;
        }
        $file_id = Str::before(Str::after($path,$app_id . "/"),"/");
        $file_id = Str::before($file_id,'.');

        if(!$file_id || !Uuid::verify($file_id)){
            return null;
        }

        $data = [
            "path" => $path,
            "app_id" => $app_id,
            "file_id" => $file_id,
            "size" => 0,
            "hash" => "",
            "is_public" => false,
        ];
        if(strtolower(data_get($u, "scheme")) == static::XCFS_SCHEMA){
            $host = data_get($u, "host","");
            if($host){
                $arr = explode(".",$host);
                if(count($arr) >= 1){
                    $data["size"] = intval($arr[0]);
                }
                if(count($arr) >= 2){
                    $data["hash"] = $arr[1];
                }
                if(count($arr) >= 3 && "public" == $arr[2]){
                    $data["is_public"] = true;
                }
            }
        }

        return $data;

    }

    static public function SignResponseUrl(string $uri,$expiryTimestamp=""){

        $data = static::ParseXcfsUri($uri);
        if(!$data){
            return $uri;
        }
        $path = $data["path"];

        $u = parse_url(static::ServiceUrl());
        $u["path"] = $path;

        switch (data_get($data,"is_public",false)){
            case false:
                $app_id = $data["app_id"];

                if(!$app_id){
                    break;
                }

                $app = static::FindAppConf($app_id);

                if(!$app){
                    break;
                }


                $secret = data_get($app, "secret");
                if(!$expiryTimestamp){
                    $expiryTimestamp = Carbon::now()->addMinutes(5)->unix();
                }

                $sign = md5($path.$expiryTimestamp.$secret);

                $u["query"] = http_build_query([
                    "e" => $expiryTimestamp,
                    "s" => $sign,
                ]);
                break;
            default:
                break;
        }



        return UtilHttp::httpBuildUrl($u);

    }


    private $_config =[];
    public function __construct()
    {
        $this->_config = config("xcfs-client");
    }

    public function generateToken(string $directory){
        $directory = trim($directory);
        if(!$directory){
            $this->setError("参数错误");
            return false;
        }
        $directory_config = data_get($this->_config,"directories.".$directory,null);
        if(!$directory_config){
            $this->setError("目录配置错误");
            return false;
        }
        $conf_app_key = data_get($directory_config,"app");
        if("" == $conf_app_key){
            $this->setError("目录应用配置错误");
            return false;
        }
        $conf_app = data_get($this->_config,"apps.".$conf_app_key);
        if(!$conf_app){
            $this->setError("应用配置错误");
            return false;
        }

        $api_url = static::ApiUrl();
        if(!$api_url){
            $this->setError("服务地址配置错误");
            return false;
        }

        $apiClient = new PrivateApiClient($api_url,data_get($conf_app,"secret",""),data_get($conf_app,"app_id",""));


        $post_data = collect($directory_config)->only([
            "directory",
            "is_public",
            "name_prefix",
            "allow_ext",
            "max_size",
        ]);


        $status = $apiClient->request("/service-api/upload-token/generate",$post_data->all(),[],"post",[]);
        if(!$status){
            $this->setError($apiClient->getError());
            return false;
        }

        $result = $apiClient->getResult('data');
        return $result;
    }
    /*
     * return array
     */
    public function verifyAndUse(array $uris){
        if(count($uris) <= 0){
            return [];
        }

        $data = [];
        $each_app_uris =[];
        foreach ($uris as $uri){
            $data[$uri] = $uri;
            $uri_data = static::ParseXcfsUri($uri);
            if(!$uri_data){
                continue;
            }
            $each_app_uris[data_get($uri_data,"app_id")][] = $uri;
        }

        if(count($each_app_uris) > 0){
            $api_url = static::ApiUrl();
            if(!$api_url){
                $this->setError("服务地址配置错误");
                return false;
            }
            foreach ($each_app_uris as $app_id => $app_uris){
                $conf_app = static::FindAppConf($app_id);
                if(!$conf_app){
                    break;
                }
                $apiClient = new PrivateApiClient($api_url,data_get($conf_app,"secret",""),data_get($conf_app,"app_id",""));

                $post_data = [
                    "file_uris"=>$app_uris
                ];

                $status = $apiClient->request("/service-api/upload-tack/verify-and-use",$post_data,[],"post",[]);
                if(!$status){
                    $this->setError($apiClient->getError());
                    break;
                }

                $result = $apiClient->getResult('data');

                foreach ($app_uris as $uri){
                    $xcfsFileInfo = Arr::exists($result,$uri) ? $result[$uri] : null;
                    if($xcfsFileInfo){
                        $data[$uri] = data_get($xcfsFileInfo,"file_uri");
                    }
                }
            }
        }


        return $data;
    }

}
